package com.industry.framework.core.generic.record;

import com.industry.framework.core.annountions.record.IdooRecordBizType;
import com.industry.framework.core.annountions.record.IdooRecordProperty;
import com.industry.framework.core.context.CoreApplicationContext;
import com.industry.framework.core.context.register.Register;
import lombok.Data;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @Author nbZhuozh
 * @Date 2025-03-25  11:10
 **/
@Component
public class RecordScanner implements Register {
    private static final Logger logger = LoggerFactory.getLogger(RecordScanner.class);

    public static Map<Class<?>,List<RecordPropertyFields>> cacheRecordMap = new HashMap<>();

    //扫描注解
    public final Class<? extends Annotation> announationClassTarget = IdooRecordBizType.class;

    // NOTES : 项目上时使用该方法 重新定义扫描位置
    public String[] getScannerPackages(){
        return new String[0];
    }

    @Override
    public void register(ApplicationContext applicationContext) {
        //仅通过容器获取
        doSpringContextScan(applicationContext);
    }

    //    @PostConstruct
    @Override
    public void register() {
        if(!ArrayUtils.isEmpty(getScannerPackages())){
            //配置包路经扫描方式
            doPackagesScan(getScannerPackages());
        }
        //spring容器获取
        doSpringContextScan();
    }

    //包扫描
    private void doPackagesScan(String[] packagesPath){
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        scanner.addIncludeFilter(new AnnotationTypeFilter(announationClassTarget));
        for (String s : packagesPath) {
            Set<BeanDefinition> components = scanner.findCandidateComponents(s);
            if(!CollectionUtils.isEmpty(components)){
                components.forEach(beanDefinition->{
                    try {
                        Class<?> clz = Class.forName(beanDefinition.getBeanClassName());
                        Field[] declaredFields = clz.getDeclaredFields();
                        initPropertyMap(clz,declaredFields);
                    } catch (ClassNotFoundException ignored) {

                    }
                });
            }
        }
    }

    //spring 容器获取
    private void doSpringContextScan(){
        ApplicationContext applicationContext = CoreApplicationContext.getApplicationContext();
        doSpringContextScan(applicationContext);
    }
    private void doSpringContextScan(ApplicationContext applicationContext){
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(announationClassTarget);
        if(!beansWithAnnotation.isEmpty()){
            beansWithAnnotation.forEach((k,v)->{
                initPropertyMap(v.getClass(),v.getClass().getDeclaredFields());
            });
        }
    }


    //propertyInit
    private void initPropertyMap(Class<?> clz , Field[] fields){
        List<RecordPropertyFields> fieldList = new ArrayList<>();
        for (Field field : fields) {
            if(field.isAnnotationPresent(IdooRecordProperty.class)){
                //禁止记录 关键数据的修改结果
                if(StringUtils.equalsAnyIgnoreCase("id")){
                    continue;
                }
                //获取注解上的 名称 及 码表中的Key
                IdooRecordProperty annotation = field.getAnnotation(IdooRecordProperty.class);
                RecordPropertyFields rf = RecordPropertyFields.of(field,annotation.value(), annotation.codeKey());
                fieldList.add(rf);
            }
        }
        //NOTE 如果类中没有配置IdooRecordProperty注解，map中不会存在当前类数据。
        if(!CollectionUtils.isEmpty(fieldList)){
            logger.info("【Idoo - RecordScannerCacheMap】 init class:{}",clz.getName());
            cacheRecordMap.put(clz,fieldList);
        }
    }

    @Data
    //IdooRecordProperty 注解中的属性
    static public class RecordPropertyFields{
        Field tempField;//原始属性
        String templateName ; //字段名称（注解）
        String codeKey; //为空则不为码表数据， 不为空时 记录 码表对应KEy
        String fieldName; //属性值(英文)
        Class<?> fieldType;

         public RecordPropertyFields(Field tempField ,String name , String codeKey , String filedName , Class<?> fieldType){
            this.templateName = name; //title
            this.codeKey = codeKey;
            this.tempField = tempField;
            this.fieldName = filedName;
            this.fieldType = fieldType;
        }
        public static RecordPropertyFields of(Field tempField ,String name , String codeKey){
            if(tempField == null){
                return null;
            }
            return new RecordPropertyFields(tempField,name,codeKey,tempField.getName(),tempField.getType());
        }
    }


    public static RecordPropertyFields findPropertyField(Class<?> clz , String fileName){
        if(cacheRecordMap.containsKey(clz)){
            List<RecordPropertyFields> recordPropertyFields = cacheRecordMap.get(clz);
            return recordPropertyFields.stream()
                    .filter(i->{return StringUtils.equals(i.getFieldName(),fileName);})
                    .findFirst().orElse(null);
        }
        return null;
    }

}
